const t = require("@babel/types")
const generator = require("@babel/generator").default
const fs = require("fs")
const { parse } = require("@babel/parser")

function getFileAstNode(filePath) {
  const str = fs.readFileSync(filePath, "utf-8")
  if (!str) {
    return null
  }
  try {
    const { program } = parse(str, {
      sourceType: "module",
      plugins: ["jsx", "typescript"]
    })
    if (!program.body.length) {
      return null
    }
    return program.body
  } catch (error) {
    return null
  }

}
function hasExportDefaultNode(node) {
  const hasDefaultNode = t.isExportDefaultDeclaration(node)
  if (!hasDefaultNode) {
    return false
  }
  const isFn = t.isFunctionDeclaration(node.declaration)
  const isClass = t.isClassDeclaration(node.declaration)
  if ((isFn || isClass) && node.declaration.id) {
    return node.declaration.id.name
  }
  const isIdentifier = t.isIdentifier(node.declaration)
  if (isIdentifier) {
    return node.declaration.name
  }
  return false
}

function hasExportNameNode(node, keyWord) {
  const isExportName = t.isExportNamedDeclaration(node)
  if (!isExportName) {
    return false
  }
  if (node.declaration && node.declaration.declarations) {
    return node.declaration.declarations.find(declarations => {
      return declarations.id.name === keyWord && t.isObjectExpression(declarations.init)
    })
  }
  return false
}

function getDefaultRouteNode(nodes, defaultName, keyWord) {
  return nodes.find(node => {
    if (
      t.isExpressionStatement(node) &&
      node.expression.left &&
      t.isMemberExpression(node.expression.left) &&
      t.isIdentifier(node.expression.left.object) &&
      node.expression.left.object.name === defaultName &&
      t.isIdentifier(node.expression.left.property) &&
      node.expression.left.property.name === keyWord
    ) {
      return true
    }
    return false
  })
}

function getRouteInfoNode(filePath, keyWord) {
  const astNodes = getFileAstNode(filePath)
  fs.writeFileSync("./test.json", JSON.stringify(astNodes))
  if (!astNodes) {
    return null
  }
  let defaultName, exportNameNode;
  astNodes.forEach(node => {
    if (!defaultName && (defaultName = hasExportDefaultNode(node))) {
      return
    }
    if (!exportNameNode && (exportNameNode = hasExportNameNode(node, keyWord))) {
      return
    }
  })
  if (exportNameNode) {
    fs.writeFileSync("./exportNameNode.json", JSON.stringify(exportNameNode))
    return exportNameNode.init
  }
  if (defaultName) {
    const defaultNode = getDefaultRouteNode(astNodes, defaultName, keyWord)
    if (defaultNode) {
      return defaultNode.expression.right
    }
  }
  return null
}
const node = getRouteInfoNode("./a.js", "route")

const body = t.variableDeclaration("const", [
  t.variableDeclarator(t.identifier("routes"), t.arrayExpression([node]))
])

/**
 * 
 * @param {Array<Object>} nodes 
 * @returns 
 */
function getAstCodeStr(nodes) {
  const { code } = generator({ type: "Program", body: nodes })
  return code
}

console.log(getAstCodeStr([body]));
